//
// 电话号格式
// 国际字冠码+区号+本地号码
//
// 电话拨号格式
// 1, 本地拨号，直接呼叫本地号码
//
// 2, 跨区拨号，0+区号+本地号码
//
// 3, 跨国拨号，出局码+国际码+区号+本地号码。
//    跨国拨号又细分两种格式：
//    1) 通用格式，"+"+国际码+区号+本地号码。
//    2) 各国出局码 + 国际码 + 区号+本地号码。各国出局码由各国制定，在中国，出局码为00；在美国，出局码为01。
// 更多资料请参考ITU的e164规范。
//
// 在拨号系统中，由多个节点的拨号网关组成，除各区、各国外，网关之间也需要出局码用于网关线路的路由识别。
// 因此，在实际的语音网关对接中，出局前缀的使用非常多，也由各网关自行识别定义。
// 例如：12593等呼叫前缀、本地短号等都是
//
// 本系统呼叫采用基本的两种呼叫格式
// 0+区号+本地号码与"+"+国际码+区号+本地号的格式，00出局码系统将转化为+号再进一步拨号。
//
package e164

type E164Num struct {
	ccode    string
	num      string
	isMobile bool
}

func (e *E164Num) IsMobile() bool {
	return e.isMobile
}

func (e *E164Num) CCode() string {
	return e.ccode
}

func (e *E164Num) Num() string {
	return e.num
}

func (e *E164Num) String() string {
	return e.ccode + e.num
}

// 生成已确认过的号码格式
func NewE164Num(ccode, tele string, isMobile bool) *E164Num {
	return &E164Num{ccode, tele, isMobile}
}

// 模糊模式
//
// ccode -- 国际码，用于识别号码中的国际码
// tele -- 用户输入的号码
// lookup 为真，使用各种方法查找原始号码中的准确号码, 并返回该号码
// 精确模式
// lookup 为假, 仅对原始号码做解析，如果不符合e164规范的，返回错误
func Search(ccode, tele string, lookup bool) (*E164Num, error) {
	newTele := getE164Num(tele)

	// 或不查找号码中的数据，任何变更号都不合法。
	if !lookup && newTele != tele {
		return nil, ErrNumFormat
	}

	// 分离国际码
	e164Num := seperateE164Num(ccode, newTele)
	e164Num.isMobile = true

	// 调用本地化驱动校验本地号码
	e164, ok := GetDriver(e164Num.ccode)
	if !ok {
		return e164Num, nil
	}
	localTele, err := e164.Search(e164Num.Num(), lookup)
	if err != nil {
		return nil, err
	}
	e164Num.num = localTele
	e164Num.isMobile = e164.IsMobile(localTele)

	return e164Num, nil
}
